<html>
  <head>
    <title>
      实体同步器
    </title>
  </head>
  <body>
    <script>
       /*
                        六、实体同步器 EntitySynchronizer基类

                                在分布式(或微服务)系统中，通常为另一个服务的实体类型订阅更改事件，因此你可以在订阅的实体更改时收到通知。

                                在这种情下，你可以使用ABP的预定义分布式事件，如上一节所述。


                                如果你的目的是存储远程实体的本地副本，你通常会订阅 创建、更新 和 删除等内置事件，并子事件处理程序中更新本地数据库。

                                ABP提供了一个预构建的 EntitySynchronizer基类，来方便你的操作。


                                现在，假设Catalog(商品清单服务)微服务中右边一个 Product实体 (可能是一个聚合根实体)，并且你希望使用本地OrderProduct实体来将
                                产品的副本保存在Order微服务中。
                                在实践中，OrderProduct类的属性将是Product属性的子集，因为并非所有的产品数据都需要在Order微服务中.此外，OrderProduct实体可能具有其他属性，
                                这些属性在Order微服务中填充和使用。


                                建议同步的第一步是在Catalog（商品清单服务）微服务中定义一个Eto类，用于传输事件数据。
                                
                                假设Product实体有一个GUID主键，你的Eto可以如下所示：

                                            [EventName("product")]
                                            public class ProductEto : EntityEto<Guid> // 标准Eto基类
                                            {
                                                // Your Product properties here...
                                            }

                                ProductEto可以放在Order(商品订购服务)微服务和 Catalog(商品清单服务) 微服务引用的 "共享项目(DLL)"中。

                                或者，如果你不想在服务之间引入常见的项目依赖，你可以将 ProductEto的副本放在Order微服务中。

                                在这种情况下，EventName 属性对于跨越两个服务映射 ProuductEto类变得至关重要 (发布和订阅时需要使用相同的事件名称);

                                定义Eto类之后，你应该将ABP配置为 Product 实体发布自动分分布式事件(创建、更新、删除)，如上一节所述：
                                                
                                            Configure<AbpDistributedEntityEventOptions>(options =>
                                            {
                                                options.AutoEventSelectors.Add<Product>();  // 允许 Product实体发布自动分布式事件
                                                options.EtoMappings.Add<Product, ProductEto>(); // 映射实体到Eto

                                            });

                                最后，你应该在Order微服务中创建一个类，派生自 EntitySynchronizer类（实体同步器类）：

                                            public class ProductSynchronizer : EntitySynchronizer<OrderProduct, Guid, ProductEto> // 集成实体同步器基类
                                            {
                                                public ProductSynchronizer(
                                                    IObjectMapper objectMapper,  // 注入 AutoMapper
                                                    IRepository<OrderProduct, Guid> repository // 注册存储
                                                    ) : base(objectMapper, repository)
                                                {
                                                }
                                            }

                                此类的要点是他订阅源实体的自动分布式事件(创建、更新、删除)，并更新本地数据库实体。

                                它适用 ObjectMapper 系统从 ProductEto 对象创建或更新 OrderProduct对象。

                                因此，你还应该配置对象映射文档以让其正常工作。

                                
                                如果你的实体有复合主键，Name你应该从EntitySynchronizer<TEntity,TSourceEntityEto> 类集成 (只是不要使用前面例子中的Guid参数)，
                                
                                并实现 FindLocalEntityAsync 以使用数据库存储在本地数据库中查找实体。

                                EntitySynchronizer与实体版本控制系统兼容（请参阅实体文档）。因此，即使接收到的事件是无序的，它也能按预期工作。
                                如果本地数据库中的实体版本比接收到的事件中的实体更新，则该事件将被忽略。
                                你应该为实体和ETO类实现IHasEntityVersion接口（对于本例，你应该为Product、ProductEto和OrderProduct类实现）。
                                如果要忽略某些类型的更改事件，可以在类的构造函数中设置IgnoreEntityCreatedEvent、IgnoreEntityUpdatedEvent和IgnoreEntityDeletedEvent。
                                
                                         eg：
                                            public class ProductSynchronizer 
                                                : EntitySynchronizer<OrderProduct, Guid, ProductEto>
                                            {
                                                public ProductSynchronizer(
                                                    IObjectMapper objectMapper,
                                                    IRepository<OrderProduct, Guid> repository
                                                    ) : base(objectMapper, repository)
                                                {
                                                    IgnoreEntityDeletedEvent = true;  // EntitySynchronizer基类中固有属性
                                                }
                                            }
                                        
                                        EntitySynchronizer 实体同步器基类中固有属性：
                                                ①、IgnoreEntityCreatedEvent（bool）
                                                ②、IgnoreEntityCreatedEvent (bool)
                                                ③、IgnoreEntityDeletedEvent (bool)

                                请注意，只有在你使用实体后，EntitySynchronizer才会自动创建、更新实体。如果你有带有存量数据的现有系统，你需要手动复制一次数据。
                                                
                    */
    </script>
  </body>
</html>